﻿// RowView.cpp: 实现文件
//

#include "pch.h"
#include "DAOTest.h"
#include "RowView.h"
#include "resource.h"


// CRowView

IMPLEMENT_DYNAMIC(CRowView, CScrollView)

CRowView::CRowView()
{
	m_nPreSelectedRow = 0;
}

CRowView::~CRowView()
{
}


BEGIN_MESSAGE_MAP(CRowView, CScrollView)
	ON_WM_LBUTTONDOWN()
	ON_WM_KEYDOWN()
	ON_WM_SIZE()
END_MESSAGE_MAP()


// CRowView 绘图

void CRowView::OnInitialUpdate()
{

	m_nPrevRowCount = GetRowCount();

	m_nPreSelectedRow = GetActiveRow();

	OnUpdate(this,0,NULL);

}

void CRowView::OnDraw(CDC* pDC)
{
	CDocument* pDoc = GetDocument();
	// TODO:  在此添加绘制代码
	if (GetRowCount() == 0)
		return;

	int nFirstRow, nLastRow;
	CRect rectClip;
	pDC->GetClipBox(&rectClip);
	RectLPToRowRange(rectClip,nFirstRow, nLastRow,TRUE);

	int nActiveRow = GetActiveRow();
	int nRow, nY;
	int nLastableRow = LastViewableRow();
	for (nRow = nFirstRow, nY = m_nRowHeight * nFirstRow; nRow<= nLastRow; nRow++, nY += m_nRowHeight)
	{
		if (nRow >= (nLastableRow - 1))
		{
			CString strWarning;
			strWarning.LoadStringW(IDS_TOO_MANY_ROWS);
			pDC->TextOutW(0,nY, strWarning);
			break;
		}

		CBrush brushBackground;
		COLORREF crOldText, crOldBackground;
		if (!pDC->IsPrinting())
		{
			if (nRow == nActiveRow)
			{
				brushBackground.CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT));
				crOldBackground = pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
				crOldText = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
			}
			else
			{
				brushBackground.CreateSolidBrush(::GetSysColor(COLOR_WINDOW));
			}

			CRect rectSelection;
			pDC->GetClipBox(&rectSelection);
			rectSelection.top = nY;
			rectSelection.bottom = nY + m_nRowHeight;
			pDC->FillRect(&rectSelection, &brushBackground);
		}

		OnDrawRow(pDC,nRow,nY,nRow == nActiveRow);

		if ((!pDC->IsPrinting())&&(nRow == nActiveRow))
		{
			pDC->SetBkColor(crOldBackground);
			pDC->SetTextColor(crOldText);
		}
	}
}

void CRowView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
	CScrollView::OnPrepareDC(pDC, pInfo);
	CalculateMetrics(pDC);
}

BOOL CRowView::OnPreparePrinting(CPrintInfo* pInfo)
{
	return DoPreparePrinting(pInfo);
}

void CRowView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
	int nPageHeight = pDC->GetDeviceCaps(VERTRES);
	CalculateMetrics(pDC);
	m_nRowPerPrintPage = nPageHeight / m_nRowHeight;
	int nPrintableRowCount = LastViewableRow() + 1;
	if (GetRowCount() < nPrintableRowCount)
	{
		nPrintableRowCount = GetRowCount();
	}
	pInfo->SetMaxPage((nPrintableRowCount + m_nRowPerPrintPage - 1)/ m_nRowPerPrintPage);
	pInfo->m_nCurPage = 1;
}

void CRowView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
	int nYTopOfPage = (pInfo->m_nCurPage - 1) * m_nRowPerPrintPage * m_nRowHeight;

	pDC->SetViewportOrg(0, nYTopOfPage);

	int nPageWidth = pDC->GetDeviceCaps(HORZRES);

	CRect rectClip = CRect(0, nYTopOfPage, nPageWidth, nYTopOfPage + m_nRowPerPrintPage * m_nRowHeight);

	pDC->IntersectClipRect(&rectClip);

	OnDraw(pDC);
}


// CRowView 诊断

#ifdef _DEBUG
void CRowView::AssertValid() const
{
	CScrollView::AssertValid();
}

#ifndef _WIN32_WCE
void CRowView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}
#endif
#endif //_DEBUG


// CRowView 消息处理程序


void CRowView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CClientDC dc(this);
	OnPrepareDC(&dc);
	dc.DPtoLP(&point);

	CRect rect(point,CSize(1,1));
	int nFirstRow, nLastRow;

	RectLPToRowRange(rect, nFirstRow, nLastRow,TRUE);

	if (nFirstRow <= GetRowCount() - 1)
	{
		ChangeSelectionToRow(nFirstRow);
	}
}


void CRowView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CRect rect;
	GetClientRect(&rect);

	CClientDC dc(this);
	dc.DPtoLP(&rect);

	switch (nChar)
	{
	case VK_HOME:
		ChangeSelectionToRow(0);
		break;
	case VK_END:
		ChangeSelectionToRow(min(GetRowCount()-1,LastViewableRow()-2));
		break;
	case VK_UP:
		ChangeSelectionNextRow(FALSE);
		break;
	case VK_DOWN:
		ChangeSelectionNextRow(TRUE);
		break;
	case VK_LEFT:
		if (rect.Width() < GetTotalSize().cx)
		{
			OnHScroll(SB_LINELEFT,0,NULL);
		}
		break;
	case VK_RIGHT:
		if (rect.Width() < GetTotalSize().cx)
		{
			OnHScroll(SB_LINERIGHT, 0, NULL);
		}
		break;
	case VK_PRIOR:
		if (rect.Height() < GetTotalSize().cy)
		{
			OnHScroll(SB_LINEUP, 0, NULL);
		}
		break;
	case VK_NEXT:
		if (rect.Height() < GetTotalSize().cy)
		{
			OnHScroll(SB_LINEDOWN, 0, NULL);
		}
		break;
	default:
		CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
		break;
	}
}


void CRowView::OnSize(UINT nType, int cx, int cy)
{
	UpdateScrollSizes();

	CScrollView::OnSize(nType, cx, cy);

	// TODO: 在此处添加消息处理程序代码
	
}

void CRowView::UpdateRow(int nValidRow)
{
	int nRowCount = GetRowCount();
	if (nRowCount != m_nPrevRowCount)
	{
		UpdateScrollSizes();
		m_nPrevRowCount = nRowCount;
	}

	CClientDC dc(this);
	OnPrepareDC(&dc);

	int nFirstRow, nLastRow;
	CRect rectClient;
	GetClientRect(&rectClient);
	dc.DPtoLP(&rectClient);
	RectLPToRowRange(rectClient, nFirstRow, nLastRow,FALSE);

	CPoint pt = GetDeviceScrollPosition();
	BOOL bNeedScroll = TRUE;
	if (nValidRow < nFirstRow)
	{
		pt.y = RowToYPos(nValidRow);
	}
	else if(nValidRow > nLastRow)
	{
		pt.y = max(0,RowToYPos(nValidRow+1) - rectClient.Height());
	}
	else
	{
		bNeedScroll = FALSE;
	}

	if (bNeedScroll)
	{
		ScrollToDevicePosition(pt);
		OnPrepareDC(&dc);
	}


	CRect rectInvalid = RowToWndRect(&dc, nValidRow);
	InvalidateRect(&rectInvalid);

	int nSelectRow = GetActiveRow();
	if (nSelectRow != m_nPreSelectedRow)
	{
		CRect rectSelectOldPos = RowToWndRect(&dc, m_nPreSelectedRow);
		InvalidateRect(&rectSelectOldPos);
		m_nPreSelectedRow = nSelectRow;
	}
}

void CRowView::CalculateMetrics(CDC* pDC)
{
	GetRowWidthHeight(pDC, m_nRowWidth, m_nRowHeight,m_nCharWidth);
}

void CRowView::UpdateScrollSizes()
{
	CRect rectClient;
	GetClientRect(&rectClient);

	CClientDC dc(this);
	CalculateMetrics(&dc);

	CSize sizeTotal(m_nRowWidth,m_nRowHeight * (min(GetRowCount(),LastViewableRow())));

	CSize sizePage(m_nRowWidth/5,max(m_nRowHeight,((rectClient.bottom/ m_nRowHeight) - 1)* m_nRowHeight));

	CSize sizeLine(m_nRowWidth/20, m_nRowHeight);

	SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
}

CRect CRowView::RowToWndRect(CDC* pDC, int nRow)
{
	CRect rectClient;
	GetClientRect(&rectClient);
	pDC->DPtoLP(&rectClient);
	CRect rect(rectClient.left,m_nRowHeight* nRow, rectClient.right, m_nRowHeight * (nRow+1));
	pDC->LPtoDP(&rect);
	return rect;
}

int CRowView::RowToYPos(int nRow)
{
	return (m_nRowHeight * nRow);
}

void CRowView::RectLPToRowRange(const CRect& rect, int& nFirstRow, int& nLastRow, BOOL bIncludePartiallyShownRows)
{
	int nRounding = bIncludePartiallyShownRows ? 0 : (m_nRowHeight - 1);
	nFirstRow = (rect.top + nRounding) / m_nRowHeight;
	nLastRow = min((rect.bottom - nRounding)/ m_nRowHeight,GetRowCount()-1);
}

int CRowView::LastViewableRow()
{
#ifdef WINDOWSNT
	return LONG_MAX / m_nRowHeight - 1;
#endif // WINDOWSNT
	return SHRT_MAX / m_nRowHeight - 1;
}

